home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / bash_114.zip / bash-1.14.2 / unwind_prot.c < prev    next >
C/C++ Source or Header  |  1993-12-08  |  7KB  |  273 lines

  1. /* I can't stand it anymore!  Please can't we just write the
  2.    whole Unix system in lisp or something? */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. /* **************************************************************** */
  23. /*                                    */
  24. /*              Unwind Protection Scheme for Bash            */
  25. /*                                    */
  26. /* **************************************************************** */
  27. #include "bashtypes.h"
  28. #include <signal.h>
  29. #include "config.h"
  30. #include "command.h"
  31. #include "general.h"
  32. #include "unwind_prot.h"
  33. #include "quit.h"
  34.  
  35. /* If CLEANUP is null, then ARG contains a tag to throw back to. */
  36. typedef struct _uwp {
  37.   struct _uwp *next;
  38.   Function *cleanup;
  39.   char *arg;
  40. } UNWIND_ELT;
  41.  
  42. static void
  43.   unwind_frame_discard_internal (), unwind_frame_run_internal (),
  44.   add_unwind_protect_internal (), remove_unwind_protect_internal (),
  45.   run_unwind_protects_internal (), without_interrupts ();
  46.  
  47. static UNWIND_ELT *unwind_protect_list = (UNWIND_ELT *)NULL;
  48.  
  49. extern int interrupt_immediately;
  50.  
  51. /* Run a function without interrupts.  This relies on the fact that the
  52.    FUNCTION cannot change the value of interrupt_immediately.  (I.e., does
  53.    not call QUIT (). */
  54. static void
  55. without_interrupts (function, arg1, arg2)
  56.      VFunction *function;
  57.      char *arg1, *arg2;
  58. {
  59.   int old_interrupt_immediately;
  60.  
  61.   old_interrupt_immediately = interrupt_immediately;
  62.   interrupt_immediately = 0;
  63.  
  64.   (*function)(arg1, arg2);
  65.  
  66.   interrupt_immediately = old_interrupt_immediately;
  67. }
  68.  
  69. /* Start the beginning of a region. */
  70. void
  71. begin_unwind_frame (tag)
  72.      char *tag;
  73. {
  74.   add_unwind_protect ((Function *)NULL, tag);
  75. }
  76.  
  77. /* Discard the unwind protects back to TAG. */
  78. void
  79. discard_unwind_frame (tag)
  80.      char *tag;
  81. {
  82.   if (unwind_protect_list)
  83.     without_interrupts (unwind_frame_discard_internal, tag, (char *)NULL);
  84. }
  85.  
  86. /* Run the unwind protects back to TAG. */
  87. void
  88. run_unwind_frame (tag)
  89.      char *tag;
  90. {
  91.   if (unwind_protect_list)
  92.     without_interrupts (unwind_frame_run_internal, tag, (char *)NULL);
  93. }
  94.  
  95. /* Add the function CLEANUP with ARG to the list of unwindable things. */
  96. void
  97. add_unwind_protect (cleanup, arg)
  98.      Function *cleanup;
  99.      char *arg;
  100. {
  101.   without_interrupts (add_unwind_protect_internal, (char *)cleanup, arg);
  102. }
  103.  
  104. /* Remove the top unwind protect from the list. */
  105. void
  106. remove_unwind_protect ()
  107. {
  108.   if (unwind_protect_list)
  109.     without_interrupts
  110.       (remove_unwind_protect_internal, (char *)NULL, (char *)NULL);
  111. }
  112.  
  113. /* Run the list of cleanup functions in unwind_protect_list. */
  114. void
  115. run_unwind_protects ()
  116. {
  117.   if (unwind_protect_list)
  118.     without_interrupts
  119.       (run_unwind_protects_internal, (char *)NULL, (char *)NULL);
  120. }
  121.  
  122. /* **************************************************************** */
  123. /*                                    */
  124. /*                        The Actual Functions                         */
  125. /*                                    */
  126. /* **************************************************************** */
  127.  
  128. static void
  129. add_unwind_protect_internal (cleanup, arg)
  130.      Function *cleanup;
  131.      char *arg;
  132. {
  133.   UNWIND_ELT *elt;
  134.  
  135.   elt = (UNWIND_ELT *)xmalloc (sizeof (UNWIND_ELT));
  136.   elt->cleanup = cleanup;
  137.   elt->arg = arg;
  138.   elt->next = unwind_protect_list;
  139.   unwind_protect_list = elt;
  140. }
  141.  
  142. static void
  143. remove_unwind_protect_internal ()
  144. {
  145.   UNWIND_ELT *elt = unwind_protect_list;
  146.  
  147.   if (elt)
  148.     {
  149.       unwind_protect_list = unwind_protect_list->next;
  150.       free (elt);
  151.     }
  152. }
  153.  
  154. static void
  155. run_unwind_protects_internal ()
  156. {
  157.   UNWIND_ELT *t, *elt = unwind_protect_list;
  158.  
  159.   while (elt)
  160.    {
  161.       /* This function can be run at strange times, like when unwinding
  162.     the entire world of unwind protects.  Thus, we may come across
  163.      an element which is simply a label for a catch frame.  Don't call
  164.      the non-existant function. */
  165.       if (elt->cleanup)
  166.     (*(elt->cleanup)) (elt->arg);
  167.  
  168.       t = elt;
  169.       elt = elt->next;
  170.       free (t);
  171.     }
  172.   unwind_protect_list = elt;
  173. }
  174.  
  175. static void
  176. unwind_frame_discard_internal (tag)
  177.      char *tag;
  178. {
  179.   UNWIND_ELT *elt;
  180.  
  181.   while (elt = unwind_protect_list)
  182.     {
  183.       unwind_protect_list = unwind_protect_list->next;
  184.       if (!elt->cleanup && (STREQ (elt->arg, tag)))
  185.     {
  186.       free (elt);
  187.       break;
  188.     }
  189.       else
  190.     free (elt);
  191.     }
  192. }
  193.  
  194. static void
  195. unwind_frame_run_internal (tag)
  196.      char *tag;
  197. {
  198.   UNWIND_ELT *elt;
  199.  
  200.   while (elt = unwind_protect_list)
  201.     {
  202.       unwind_protect_list = elt->next;
  203.  
  204.       /* If tag, then compare. */
  205.       if (!elt->cleanup)
  206.     {
  207.       if (STREQ (elt->arg, tag))
  208.         {
  209.           free (elt);
  210.           break;
  211.         }
  212.       free (elt);
  213.       continue;
  214.     }
  215.       else
  216.     {
  217.       (*(elt->cleanup)) (elt->arg);
  218.       free (elt);
  219.     }
  220.     }
  221. }
  222.  
  223. /* Structure describing a saved variable and the value to restore it to. */
  224. typedef struct {
  225.   int *variable;
  226.   char *desired_setting;
  227.   int size;
  228. } SAVED_VAR;
  229.  
  230. /* Restore the value of a variable, based on the contents of SV.  If
  231.    sv->size is greater than sizeof (int), sv->desired_setting points to
  232.    a block of memory SIZE bytes long holding the value, rather than the
  233.    value itself.  This block of memory is copied back into the variable. */
  234. static void
  235. restore_variable (sv)
  236.      SAVED_VAR *sv;
  237. {
  238.   if (sv->size > sizeof (int))
  239.     {
  240.       bcopy ((char *)sv->desired_setting, (char *)sv->variable, sv->size);
  241.       free (sv->desired_setting);
  242.     }
  243.   else
  244.     *(sv->variable) = (int)sv->desired_setting;
  245.  
  246.   free (sv);
  247. }
  248.  
  249. /* Save the value of a variable so it will be restored when unwind-protects
  250.    are run.  VAR is a pointer to the variable.  VALUE is the value to be
  251.    saved.  SIZE is the size in bytes of VALUE.  If SIZE is bigger than what
  252.    can be saved in an int, memory will be allocated and the value saved
  253.    into that using bcopy (). */
  254. void
  255. unwind_protect_var (var, value, size)
  256.      int *var;
  257.      char *value;
  258.      int size;
  259. {
  260.   SAVED_VAR *s = (SAVED_VAR *)xmalloc (sizeof (SAVED_VAR));
  261.  
  262.   s->variable = var;
  263.   if (size > sizeof (int))
  264.     {
  265.       s->desired_setting = (char *)xmalloc (size);
  266.       bcopy (value, (char *)s->desired_setting, size);
  267.     }
  268.   else
  269.     s->desired_setting = value;
  270.   s->size = size;
  271.   add_unwind_protect ((Function *)restore_variable, (char *)s);
  272. }
  273.